package com.wg.net;

import com.wg.core.properties.PropertiesMgr;
import cn.hutool.core.util.StrUtil;

/**
 * 网络全局配置管理器
 * <p>
 * 负责存储和管理HTTP、TCP、SSL等网络相关配置，支持从属性文件动态加载和重载配置。
 *
 * @author 少爷123
 */
public class NetConfig {
    // ------------------------------ 常量定义 ------------------------------
    /**
     * HTTP默认端口
     */
    public static final int DEFAULT_HTTP_PORT = 0;
    /**
     * TCP默认端口
     */
    public static final int DEFAULT_TCP_PORT = 0;
    /**
     * 默认最大内容长度（1MB）
     */
    public static final int DEFAULT_MAX_CONTENT_LENGTH = 1024 * 1024; // 1MB
    /**
     * 默认低水位（32KB）
     */
    public static final int DEFAULT_LOW_WATER_MARK = 32 * 1024; // 32KB
    /**
     * 默认高水位（64KB）
     */
    public static final int DEFAULT_HIGH_WATER_MARK = 64 * 1024; // 64KB
    /**
     * 默认工作线程数（参考Netty最佳实践）
     */
    public static final int DEFAULT_WORK_THREADS = Runtime.getRuntime().availableProcessors() * 2;
    /**
     * 默认请求间隔（200ms）
     */
    public static final int DEFAULT_REQUEST_INTERVAL = 200;
    /**
     * 默认Gzip压缩阈值（5KB）
     */
    public static final int DEFAULT_GZIP_THRESHOLD = 5 * 1024; // 5KB
    /**
     * 默认连接队列大小（65535）
     */
    public static final int DEFAULT_BACKLOG_SIZE = 65535;
    /**
     * 默认关闭超时时间（60秒）
     */
    public static final int DEFAULT_SHUTDOWN_TIMEOUT = 60;
    /**
     * 默认最大帧长度（1MB）
     */
    public static final int DEFAULT_MAX_FRAME_LENGTH = 1024 * 1024;

    // ------------------------------ 配置字段 ------------------------------
    /**
     * HTTP服务端口
     */
    private int httpPort;
    /**
     * 是否启用SSL
     */
    private boolean ssl;
    /**
     * SSL证书文件名（支持.pfx/.jks）
     */
    private String sslFileName;
    /**
     * SSL私钥路径
     */
    private String sslPrivateKey;
    /**
     * TCP监听端口
     */
    private int tcpPort;
    /**
     * TCP连接队列大小（backlog）
     */
    private int backlogSize;
    /**
     * 是否允许地址重用
     */
    private boolean reuseAddr;
    /**
     * 是否启用长连接（Keep-Alive）
     */
    private boolean keepAlive;
    /**
     * 是否禁用Nagle算法（TCP No Delay）
     */
    private boolean tcpNoDelay;
    /**
     * 子通道是否启用长连接
     */
    private boolean childKeepAlive;
    /**
     * 子通道是否禁用Nagle算法
     */
    private boolean childTcpNoDelay;
    /**
     * 是否启用分块写（支持大文件传输）
     */
    private boolean chunkedWriteEnabled;
    /**
     * 读取超时时间（秒，0表示不超时）
     */
    private int readTimeout;
    /**
     * 是否启用SSL客户端认证
     */
    private boolean sslClientAuth;
    /**
     * 优雅关闭超时时间（秒）
     */
    private int shutdownTimeout;
    /**
     * WebSocket路径
     */
    private String webPath;
    /**
     * 无操作断开超时（秒，0表示不生效）
     */
    private int disconnectTimeout;
    /**
     * 网络封包日志是否启用
     */
    private boolean logActive;
    /**
     * HTTP最大内容长度（字节）
     */
    private int maxContentLength;
    /**
     * Netty低水位（字节）
     */
    private int lowWaterMark;
    /**
     * Netty高水位（字节）
     */
    private int highWaterMark;
    /**
     * Netty工作线程数
     */
    private int workThreads;
    /**
     * 请求间隔（毫秒，防止恶意请求）
     */
    private int requestInterval;
    /**
     * Gzip压缩阈值（字节）
     */
    private int gzipThreshold;
    /**
     * 最大帧长度（字节）
     */
    private int maxFrameLength;

    // ------------------------------ 单例管理 ------------------------------
    private static final class Singleton {
        private static final NetConfig INSTANCE = new NetConfig();
    }

    /**
     * 获取全局单例实例（线程安全）
     */
    public static NetConfig getInstance() {
        return Singleton.INSTANCE;
    }

    // ------------------------------ 构造与初始化 ------------------------------

    /**
     * 私有构造函数（防止外部实例化）
     */
    private NetConfig() {
        loadDefaultConfig();
        loadPropertiesConfig();
        validateConfig();
    }

    /**
     * 加载默认配置（硬编码的默认值）
     */
    private void loadDefaultConfig() {
        httpPort = DEFAULT_HTTP_PORT;
        tcpPort = DEFAULT_TCP_PORT;
        backlogSize = DEFAULT_BACKLOG_SIZE;
        reuseAddr = true;
        keepAlive = true;
        tcpNoDelay = true;
        childKeepAlive = true;
        childTcpNoDelay = true;
        chunkedWriteEnabled = true;
        disconnectTimeout = 30;
        logActive = false;
        maxContentLength = DEFAULT_MAX_CONTENT_LENGTH;
        lowWaterMark = DEFAULT_LOW_WATER_MARK;
        highWaterMark = DEFAULT_HIGH_WATER_MARK;
        workThreads = DEFAULT_WORK_THREADS;
        requestInterval = DEFAULT_REQUEST_INTERVAL;
        gzipThreshold = DEFAULT_GZIP_THRESHOLD;
        shutdownTimeout = DEFAULT_SHUTDOWN_TIMEOUT;
        maxFrameLength = DEFAULT_MAX_FRAME_LENGTH;

    }

    /**
     * 从属性文件加载动态配置（覆盖默认值）
     */
    private void loadPropertiesConfig() {
        httpPort = PropertiesMgr.getInt(NetConstant.HTTP_PORT, httpPort);
        ssl = PropertiesMgr.getBool(NetConstant.HTTP_SSL, false);
        tcpPort = PropertiesMgr.getInt(NetConstant.TCP_PORT, tcpPort);
        webPath = PropertiesMgr.getStr(NetConstant.WEBSOCKET_PATH, webPath);
        disconnectTimeout = PropertiesMgr.getInt(NetConstant.DISCONNECT_TIMEOUT, disconnectTimeout);
        logActive = PropertiesMgr.getBool(NetConstant.LOG_ACTIVE, logActive);
        maxContentLength = PropertiesMgr.getInt(NetConstant.HTTP_MAX_CONTENT_LENGTH, maxContentLength);
        lowWaterMark = PropertiesMgr.getInt(NetConstant.LOW_WATER_MARK, lowWaterMark);
        highWaterMark = PropertiesMgr.getInt(NetConstant.HIGH_WATER_MARK, highWaterMark);
        workThreads = PropertiesMgr.getInt(NetConstant.WORKER_THREADS, workThreads);
        sslFileName = PropertiesMgr.getStr(NetConstant.HTTP_SSL_FILENAME, sslFileName);
        sslPrivateKey = PropertiesMgr.getStr(NetConstant.HTTP_SSL_PRIVATE_KEY, sslPrivateKey);
        requestInterval = PropertiesMgr.getInt(NetConstant.REQUEST_INTERVAL, requestInterval);
        gzipThreshold = PropertiesMgr.getInt(NetConstant.GZIP_THRESHOLD, gzipThreshold);
        backlogSize = PropertiesMgr.getInt(NetConstant.BACKLOG_SIZE, backlogSize);
        reuseAddr = PropertiesMgr.getBool(NetConstant.IS_REUSE_ADDR, reuseAddr);
        keepAlive = PropertiesMgr.getBool(NetConstant.IS_KEEP_ALIVE, keepAlive);
        tcpNoDelay = PropertiesMgr.getBool(NetConstant.IS_TCP_NO_DELAY, tcpNoDelay);
        childKeepAlive = PropertiesMgr.getBool(NetConstant.IS_CHILD_KEEP_ALIVE, childKeepAlive);
        childTcpNoDelay = PropertiesMgr.getBool(NetConstant.IS_CHILD_TCP_NO_DELAY, childTcpNoDelay);
        chunkedWriteEnabled = PropertiesMgr.getBool(NetConstant.IS_CHUNKED_WRITE_ENABLED, chunkedWriteEnabled);
        readTimeout = PropertiesMgr.getInt(NetConstant.READ_TIMEOUT, readTimeout);
        sslClientAuth = PropertiesMgr.getBool(NetConstant.SSL_CLIENT_AUTH, sslClientAuth);
        shutdownTimeout = PropertiesMgr.getInt(NetConstant.SHUTDOWN_TIMEOUT, shutdownTimeout);
        maxFrameLength = PropertiesMgr.getInt(NetConstant.MAX_FRAME_LENGTH, maxFrameLength);

    }

    /**
     * 校验配置有效性（关键配置项检查）
     */
    private void validateConfig() {
        // 校验HTTP端口范围
        if (httpPort < 0 || httpPort > 65535) {
            throw new IllegalStateException("HTTP端口非法，范围应为0-65535，当前值: " + httpPort);
        }

        // 校验TCP端口范围
        if (tcpPort < 0 || tcpPort > 65535) {
            throw new IllegalStateException("TCP端口非法，范围应为0-65535，当前值: " + tcpPort);
        }

        // 校验工作线程数合理性
        if (workThreads <= 0) {
            throw new IllegalStateException("工作线程数必须大于0，当前值: " + workThreads);
        }

        // 校验SSL配置一致性（启用SSL但未配置证书）
        if (ssl && (StrUtil.isBlank(sslFileName) || StrUtil.isBlank(sslPrivateKey))) {
            throw new IllegalStateException("SSL启用但未配置证书文件或私钥");
        }
    }

    /**
     * 获取HTTP服务端口
     *
     * @return HTTP端口（0表示自动分配）
     */
    public int getHttpPort() {
        return httpPort;
    }

    /**
     * 是否启用SSL加密
     *
     * @return 启用返回true，否则false
     */
    public boolean isSsl() {
        return ssl;
    }

    /**
     * 获取SSL证书文件名（支持.pfx/.jks）
     *
     * @return 证书文件名（未启用SSL时为空）
     */
    public String getSslFileName() {
        return sslFileName;
    }

    /**
     * 获取SSL私钥路径
     *
     * @return 私钥路径（未启用SSL时为空）
     */
    public String getSslPrivateKey() {
        return sslPrivateKey;
    }

    /**
     * 获取TCP监听端口
     *
     * @return TCP端口（0表示自动分配）
     */
    public int getTcpPort() {
        return tcpPort;
    }

    /**
     * 获取WebSocket路径
     *
     * @return WebSocket路径（默认: "/"）
     */
    public String getWebPath() {
        return webPath;
    }

    /**
     * 获取无操作断开超时时间（秒）
     *
     * @return 超时时间（0表示不生效）
     */
    public int getDisconnectTimeout() {
        return disconnectTimeout;
    }

    /**
     * 是否启用网络封包日志
     *
     * @return 启用返回true，否则false
     */
    public boolean isLogActive() {
        return logActive;
    }

    /**
     * 获取HTTP最大内容长度（字节）
     *
     * @return 最大内容长度（默认: 1MB）
     */
    public int getMaxContentLength() {
        return maxContentLength;
    }

    /**
     * 获取Netty低水位（字节）
     *
     * @return 低水位（默认: 32KB）
     */
    public int getLowWaterMark() {
        return lowWaterMark;
    }

    /**
     * 获取Netty高水位（字节）
     *
     * @return 高水位（默认: 64KB）
     */
    public int getHighWaterMark() {
        return highWaterMark;
    }

    /**
     * 获取Netty工作线程数
     *
     * @return 工作线程数（默认: CPU核心数×2）
     */
    public int getWorkThreads() {
        return workThreads;
    }

    /**
     * 获取SSL客户端认证开关
     *
     * @return 启用返回true，否则false
     */
    public boolean isSslClientAuth() {
        return sslClientAuth;
    }

    /**
     * 获取优雅关闭超时时间（秒）
     *
     * @return 超时时间（默认: 60秒）
     */
    public int getShutdownTimeout() {
        return shutdownTimeout;
    }

    // 其他字段的Getter方法（省略，按相同模式补充）...
    public int getBacklogSize() {
        return backlogSize;
    }

    public boolean isReuseAddr() {
        return reuseAddr;
    }

    public boolean isKeepAlive() {
        return keepAlive;
    }

    public boolean isTcpNoDelay() {
        return tcpNoDelay;
    }

    public boolean isChildKeepAlive() {
        return childKeepAlive;
    }

    public boolean isChildTcpNoDelay() {
        return childTcpNoDelay;
    }

    public boolean isChunkedWriteEnabled() {
        return chunkedWriteEnabled;
    }

    public int getReadTimeout() {
        return readTimeout;
    }

    public int getRequestInterval() {
        return requestInterval;
    }

    public int getGzipThreshold() {
        return gzipThreshold;
    }

    public int getMaxFrameLength() {
        return maxFrameLength;
    }

}